package net.towee.client.com.stuff.presenter;

import java.util.ArrayList;
import java.util.List;

import net.towee.client.ToweeGinjector;
import net.towee.client.com.stuff.GroupShower;
import net.towee.client.com.stuff.GroupsFinder;
import net.towee.client.com.stuff.HasGroupEnterHandlers;
import net.towee.client.managers.AccountHelper;
import net.towee.client.managers.GroupsManager;
import net.towee.model.account.AccountGroup;
import net.towee.model.group.GroupIdentity;
import net.towee.model.group.GroupProfile;
import net.towee.model.utils.Pair;

import com.google.common.base.Preconditions;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.HasOpenHandlers;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.inject.Inject;

public class GroupsFinderPresenter implements ChangeHandler, ClickHandler, GroupsFinder,
		OpenHandler<Pair<GroupProfile, HasWidgets>> {

	public interface Display extends IsWidget {
		HasChangeHandlers getSearchArea();

		String getSearchString();

		void addGroup(GroupProfile group, boolean isInGroup);

		HasOpenHandlers<Pair<GroupProfile, HasWidgets>> getGroupOpenHandlers();

		HasClickHandlers getMyGroupsButton();
		
		HasClickHandlers getAllGroupsButton();

		HasClickHandlers getMoreResultButton();

		void onStartSearching();

		void onEndSearching();

		void clearGroups();
		
		void noMore();

		void showEmptyResult();
	}

	// Injected
	private final GroupsManager groupsManager;
	private final Display display;
	private final AccountHelper account;
	private final ToweeGinjector injector;

	private int offset = 0;
	private final int limit = 15;
	
	private enum DISPLAY_TYPE {MY, SEARCH, ALL};
	private DISPLAY_TYPE typeOfDisplay;
	
	private final AsyncCallback<List<GroupProfile>> asyncHandler = new AsyncCallback<List<GroupProfile>>() {
		@Override
		public void onFailure(Throwable caught) {
		}

		@Override
		public void onSuccess(List<GroupProfile> result) {
			display.onEndSearching();
			
			if(offset == 0)
				display.clearGroups();

			if(!result.isEmpty())
				for (GroupProfile prof : result) 
					display.addGroup(prof, account.isMemeberOfGroups(prof.getId()));
			else if( offset == 0 )
				display.showEmptyResult();
			
			offset += limit;
			
			if( result.size() < limit )
				display.noMore();
		}
	};

	@Inject
	public GroupsFinderPresenter(Display display, GroupsManager groupsManager, AccountHelper account,
			ToweeGinjector injector) {
		this.groupsManager = groupsManager;
		this.account = account;
		this.display = display;
		this.injector = injector;

		display.getSearchArea().addChangeHandler(this);
		display.getMoreResultButton().addClickHandler(this);
		display.getMyGroupsButton().addClickHandler(this);
		display.getAllGroupsButton().addClickHandler(this);
		display.getGroupOpenHandlers().addOpenHandler(this);
	}

	@Override
	public void go(HasWidgets container) {
		container.clear();
		container.add(display.asWidget());
		
		if(typeOfDisplay == null) {
			offset = 0;
			showAllGroups();
		}
	}

	private void showAllGroups() {
		typeOfDisplay = DISPLAY_TYPE.ALL;
		
		// Display some loading bar
		display.onStartSearching();
		groupsManager.getAllGroups(offset, limit, asyncHandler);
	}

	@Override
	public void onChange(ChangeEvent event) {
		// Set zero offset
		offset = 0;

		// Find groups
		findGroups();
	}
	
	private void findGroups() {
		typeOfDisplay = DISPLAY_TYPE.SEARCH;
		
		// Display some loading bar
		display.onStartSearching();
		groupsManager.findGroup(display.getSearchString(), offset, limit, asyncHandler);
	}
	
	private void showMyGroups() {
		typeOfDisplay = DISPLAY_TYPE.MY;
		
		// Create set of ids
		List<String> groupIds = new ArrayList<String>();
		for(AccountGroup g : account.getAccount().getGroups().getGroupsList()) 
			groupIds.add( g.getGroupIdentity().getId() );

		// Display some loading bar
		display.onStartSearching();
		
		// Get groups
		groupsManager.getGroupsByIds(groupIds, new AsyncCallback<List<GroupProfile>>(){

			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(List<GroupProfile> result) {
				display.onEndSearching();
				display.clearGroups();
				display.noMore();
				
				if (result.isEmpty())
					display.showEmptyResult();
				else {
					for (GroupProfile prof : result) 
						display.addGroup(prof, true);
				}
			}
			
		});
	}
	
	@Override
	public void onClick(ClickEvent event) {
		Object source = event.getSource();
		
		if(source.equals( display.getMoreResultButton() )) {
			switch(typeOfDisplay){ 
			case SEARCH:
				findGroups();	
				break;
			case ALL:
				showAllGroups();
				break;
			}
		}
		else if(source.equals( display.getAllGroupsButton() )) {
			offset = 0;
			showAllGroups();
		}
		else {
			offset = 0;
			showMyGroups();
		}
	}

	@Override
	public void onOpen(OpenEvent<Pair<GroupProfile, HasWidgets>> event) {
		GroupShower shower = injector.getGroupShower();
		shower.setGroupProfile( event.getTarget().getFirst() );
		shower.go( event.getTarget().getSecond() );
	}
}
